{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4de4e022",
   "metadata": {},
   "source": [
    "# Composition\n",
    "\n",
    "LangChain provides a user friendly interface for composing different parts of prompts together. You can do this with either string prompts or chat prompts. Constructing prompts this way allows for easy reuse of components."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3190650",
   "metadata": {},
   "source": [
    "## String prompt composition\n",
    "\n",
    "When working with string prompts, each template is joined together. You can work with either prompts directly or strings (the first element in the list needs to be a prompt)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "69b17f05",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d6ac7a48",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = (\n",
    "    PromptTemplate.from_template(\"Tell me a joke about {topic}\")\n",
    "    + \", make it funny\"\n",
    "    + \"\\n\\nand in {language}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "348d7131",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['language', 'topic'], output_parser=None, partial_variables={}, template='Tell me a joke about {topic}, make it funny\\n\\nand in {language}', template_format='f-string', validate_template=True)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "dbba24ba",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tell me a joke about sports, make it funny\\n\\nand in spanish'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt.format(topic=\"sports\", language=\"spanish\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8239bf42",
   "metadata": {},
   "source": [
    "You can also use it in an LLMChain, just like before."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "bb11649a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "from langchain.chat_models import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "2dd36787",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "2c12ba34",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = LLMChain(llm=model, prompt=prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a1559246",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'¿Por qué el futbolista llevaba un paraguas al partido?\\n\\nPorque pronosticaban lluvia de goles.'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(topic=\"sports\", language=\"spanish\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e4f6a8a",
   "metadata": {},
   "source": [
    "## Chat prompt composition"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a50ce9b8",
   "metadata": {},
   "source": [
    "A chat prompt is made up a of a list of messages. Purely for developer experience, we've added a convinient way to create these prompts. In this pipeline, each new element is a new message in the final prompt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a180f75",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema import AIMessage, HumanMessage, SystemMessage"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8554bae5",
   "metadata": {},
   "source": [
    "First, let's initialize the base ChatPromptTemplate with a system message. It doesn't have to start with a system, but it's often good practice"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cab8dd65",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = SystemMessage(content=\"You are a nice pirate\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30656ef8",
   "metadata": {},
   "source": [
    "You can then easily create a pipeline combining it with other messages *or* message templates.\n",
    "Use a `Message` when there is no variables to be formatted, use a `MessageTemplate` when there are variables to be formatted. You can also use just a string (note: this will automatically get inferred as a HumanMessagePromptTemplate.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a2ddd0a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_prompt = (\n",
    "    prompt + HumanMessage(content=\"hi\") + AIMessage(content=\"what?\") + \"{input}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72294e1b",
   "metadata": {},
   "source": [
    "Under the hood, this creates an instance of the ChatPromptTemplate class, so you can use it just as you did before!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "297932de",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[SystemMessage(content='You are a nice pirate', additional_kwargs={}),\n",
       " HumanMessage(content='hi', additional_kwargs={}, example=False),\n",
       " AIMessage(content='what?', additional_kwargs={}, example=False),\n",
       " HumanMessage(content='i said hi', additional_kwargs={}, example=False)]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_prompt.format_messages(input=\"i said hi\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "850357c0",
   "metadata": {},
   "source": [
    "You can also use it in an LLMChain, just like before."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "710d6b15",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "from langchain.chat_models import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d363c2a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "88393b87",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = LLMChain(llm=model, prompt=new_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "8492cfa9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Oh, hello! How can I assist you today?'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"i said hi\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58196f6b",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
